package com.terrier.ui.core
{
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.display.Sprite;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    use namespace wx_internal;

    /**
     * 可视化组件的基类,提供了许多访问 Flash Player Native实现的方法;
     * @author Jarvis.weng
     */
    public class WxSprite extends Sprite
    {
        /**
         * 构造函数
         */
        public function WxSprite()
        {
            super();
        }

        //------------------------------------------------------
        //
        // public method
        //
        //------------------------------------------------------

        /**
         * 检测显示对象是否和鼠标指针相交或者重叠.
         * @param exactly 是否采用精确检测. 默认为false. 只考虑显示对象的边框. 如果为true, 则将考虑显示对象的实际形状
         * (内部使用位图来绘制显示对象, 然后做位图的像素透明检测, 效率较低)
         * @return 如果相交或者重叠, 则为true; 否则为false;
         */
        public function mouseHitTest(exactly:Boolean = false):Boolean
        {
            if (this.stage == null)
            {
                return false;
            }

            var hit:Boolean = this.hitTestPoint(this.stage.mouseX, this.stage.mouseY, true);

            if (hit && exactly)
            {
                var target:DisplayObject = (hitArea == null ? this : hitArea);
                var targetRect:Rectangle = target.getBounds(target);
                var targetBmpData:BitmapData = new BitmapData(Math.max(1, targetRect.width),
                                                              Math.max(1, targetRect.height), true, 0);
                var mat:Matrix = new Matrix(1, 0, 0, 1, -targetRect.x, -targetRect.y);
                targetBmpData.draw(target, mat);

                var color:uint = targetBmpData.getPixel32(target.mouseX - targetRect.x, target.mouseY - targetRect.y);
                targetBmpData.dispose();
                return color != 0x0;
            }
            else
            {
                return hit;
            }
        }

        /**
         * 将 DisplayObject 子对象添加到指定的 DisplayObject子对象的上方
         * @param child 将要添加的 DisplayObject 子对象
         * @param targetChild 作为参照的 DisplayObject 子对象
         */
        public function addChildAbove(child:DisplayObject, targetChild:DisplayObject):void
        {
            var index:int = getChildIndex(targetChild);
            addChildAt(child, index + 1);
        }

        /**
         * 将 DisplayObject 子对象添加到指定的 DisplayObject子对象的下方
         * @param child 将要添加的 DisplayObject 子对象
         * @param targetChild 作为参照的 DisplayObject 子对象
         */
        public function addChildBelow(child:DisplayObject, targetChild:DisplayObject):void
        {
            var index:int = getChildIndex(targetChild);
            addChildAt(child, index);
        }

        /**
         * 用新的子对象替换现有的子对象
         * @param oldChild 旧的子对象
         * @param newChild 新的子对象
         */
        public function replaceChild(newChild:DisplayObject, oldChild:DisplayObject):void
        {
            var index:int = getChildIndex(oldChild);
            removeChild(oldChild);
            addChildAt(newChild, index);
        }

        /**
         * 删除所有子对象
         */
        public function removeAllChild():void
        {
            while (numChildren > 0)
            {
                removeChildAt(0);
            }
        }

        /**
         * 安全地删除子对象, 相对于<code>removeChild()</code>方法, 这个方法在删除子对象之前,会检测这个子对象是否在子对象列表中.
         * 如果子对象为空或者不存在于子对象列表中, 不会引发异常.
         * @param child 子对象
         * @return 被删除的子对象
         */
        public function removeChildSafely(child:DisplayObject):DisplayObject
        {
            return hasChild(child) ? removeChild(child) : child;
        }

        /**
         * 检测 child 对象是否为该显示对象的子项
         * (搜索范围仅包括子项，不包括整个显示列表，请注意和<code>contains</code>方法的区别)
         *
         * @param child 要检测的子对象
         *
         * @return 如果 child 对象是显示对象的子项，返回 ture；否则返回 false。
         *
         * @see flash.display.DisplayObjectContainer.contains()
         */
        public function hasChild(child:DisplayObject):Boolean
        {
            return child == null ? false : child.parent == this;
        }

        //------------------------------------------------------
        // wx_internal method
        //
        // These methods allows access to the Flash Player's native implementation methods
        // Note that these "base methods" is final and cannot be overridden,
        // so you can count on them to reflect what is happening at the player level.
        //
        // 这些方法 用于访问 Flash Player 的 native方法
        // 这些"基本方法"是 final的，不可重写(覆盖)
        // 所以可以依靠这些属性来反映播放器级别的变化
        //------------------------------------------------------

        /**
         *  @private
         */
        wx_internal final function $contains(child:DisplayObject):Boolean
        {
            return super.contains(child);
        }

        /**
         *  @private
         */
        wx_internal final function $addChild(child:DisplayObject):DisplayObject
        {
            return super.addChild(child);
        }

        /**
         *  @private
         */
        wx_internal final function $addChildAt(child:DisplayObject, index:int):DisplayObject
        {
            return super.addChildAt(child, index);
        }

        /**
         *  @private
         */
        wx_internal final function $removeChild(child:DisplayObject):DisplayObject
        {
            return super.removeChild(child);
        }

        /**
         *  @private
         */
        wx_internal final function $removeChildAt(index:int):DisplayObject
        {
            return super.removeChildAt(index);
        }

        /**
         *  @private
         */
        wx_internal final function $getChildAt(index:int):DisplayObject
        {
            return super.getChildAt(index);
        }

        /**
         *  @private
         */
        wx_internal final function $getChildByName(name:String):DisplayObject
        {
            return super.getChildByName(name);
        }

        /**
         *  @private
         */
        wx_internal final function $getChildIndex(child:DisplayObject):int
        {
            return super.getChildIndex(child);
        }

        /**
         *  @private
         */
        wx_internal final function $getObjectsUnderPoint(point:Point):Array
        {
            return super.getObjectsUnderPoint(point);
        }

        /**
         *  @private
         */
        wx_internal final function $setChildIndex(child:DisplayObject, index:int):void
        {
            super.setChildIndex(child, index);
        }

        /**
         *  @private
         */
        wx_internal final function $swapChildren(child1:DisplayObject, child2:DisplayObject):void
        {
            super.swapChildren(child1, child2);
        }

        /**
         *  @private
         */
        wx_internal final function $swapChildrenAt(index1:int, index2:int):void
        {
            super.swapChildrenAt(index1, index2);
        }

        //------------------------------------------------------
        // wx_internal property
        //
        // These properties allows access to the Flash Player's native implementation properties
        // Note that these "base properties" is final and cannot be overridden,
        // so you can count on them to reflect what is happening at the player level.
        // 
        // 这些属性 用于访问 Flash Player 的 native属性
        // 这些"基本属性"是 final的，不可重写(覆盖)
        // 所以可以依靠这些属性来反映播放器级别的变化
        //------------------------------------------------------

        /**
         *  @private
         */
        wx_internal final function get $parent():DisplayObjectContainer
        {
            return super.parent;
        }

        /**
         *  @private
         */
        wx_internal final function get $x():Number
        {
            return super.x;
        }

        /**
         *  @private
         */
        wx_internal final function set $x(value:Number):void
        {
            super.x = value;
        }

        /**
         *  @private
         */
        wx_internal final function get $y():Number
        {
            return super.y;
        }

        /**
         *  @private
         */
        wx_internal final function set $y(value:Number):void
        {
            super.y = value;
        }

        /**
         *  @private
         */
        wx_internal final function get $width():Number
        {
            return super.width;
        }

        /**
         *  @private
         */
        wx_internal final function set $width(value:Number):void
        {
            super.width = value;
        }

        /**
         *  @private
         */
        wx_internal final function get $height():Number
        {
            return super.height;
        }

        /**
         *  @private
         */
        wx_internal final function set $height(value:Number):void
        {
            super.height = value;
        }

        /**
         *  @private
         */
        wx_internal final function get $visible():Boolean
        {
            return super.visible;
        }

        /**
         *  @private
         */
        wx_internal final function set $visible(value:Boolean):void
        {
            super.visible = value;
        }

        /**
         *  @private
         */
        wx_internal final function get $numChildren():Number
        {
            return super.numChildren;
        }
    }
}
